﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vim25Api;

namespace VmwareSeacher
{
    class SearchFilter : IExecFilter
    {
        bool is_found = false;
        VmSearcher _vms;
        string strmac;
        public SearchFilter(VmSearcher vms)
        {
            _vms = vms;
        }
        VmwreIterator curVi;
        ManagedObjectReference curDatecenterMor;
        ManagedObjectReference curDomainMor;
        ManagedObjectReference curHostMor;
        ManagedObjectReference curVmMor;

        string curdatecenterName;
        string curhostsname;
        string curvmname;

        ArrayList oplist = new ArrayList();
        enum Op_methd
        {
            EQUAL,
            NOT_EQUAL,
            AND,
            OR,
        };
        struct express_op
        {
            public string name;
            public Op_methd method;
            public string value;
            public Op_methd cond;
            //public express_op()
            //{
            //    name = null;
            //    method = Op_methd.EQUAL;
            //    value = null;
            //    cond = Op_methd.AND;
            //}
        }

        public int ParseCmd(string express)
        {
            string[] args = express.Split(new Char[] { ' ' });
            for (int i = 0; i < args.Length; i += 3)
            {
                
                express_op op = new express_op();
                string condname = args[i];
                if(condname.Equals("||") == true)
                {
                    op.cond = Op_methd.OR;
                    i++;
                }
                else if (condname.Equals("&&") == true)
                {
                    op.cond = Op_methd.AND;
                    i++;
                }
                else
                {
                    op.cond = Op_methd.AND;
                }


                string name = args[i + 0];
                if (String.Compare(name, "datacenter", true) == 0
                    || String.Compare(name, "domain", true) == 0
                    || String.Compare(name, "host", true) == 0
                    || String.Compare(name, "vm", true) == 0
                    || String.Compare(name, "mac", true) == 0)
                {
                    op.name = name;
                }
                else
                {
                    throw new Exception("express syntax error! expect datacenter | domain | host | vm | mac on pos " + i + " but it was " + name);
                }
                string methodname = args[i + 1];
                if (String.Compare(methodname, "==", true) == 0)
                {
                    op.method = Op_methd.EQUAL;
                }
                else if (String.Compare(methodname, "!=", true) == 0)
                {
                    op.method = Op_methd.NOT_EQUAL;
                }
                else
                {
                    throw new Exception("express syntax error! expect == | != on pos " + (i + 1) + " but it was " + methodname);
                }
                string value = args[i + 2];
                if (value.Equals("") == true)
                {
                    throw new Exception("express syntax error! value can't be null on pos " + (i + 2));
                }
                else
                {
                    if (String.Compare(name, "mac", true) == 0)
                    {
                        value = value.Trim().Replace('-', ':');
                    }
                    op.value = value;
                }
                oplist.Add(op);
            }
            return 0;

        }

        RT_VALUE STR_CMP_RETURN(string a, string b, Op_methd method, Op_methd cond)
        {
            if (method == Op_methd.EQUAL && cond == Op_methd.AND)
            {
                if (a.Equals(b) == true)
                {
                    return RT_VALUE.CONTINUE;
                }
                else
                {
                    return RT_VALUE.NEXT;
                }
            }
            else if (method == Op_methd.NOT_EQUAL && cond == Op_methd.AND)
            {
                if (a.Equals(b) == true)
                {
                    return RT_VALUE.NEXT;
                }
                else
                {
                    return RT_VALUE.CONTINUE;
                }
            }
            else //OR 未关注
            {                
                return RT_VALUE.CONTINUE;
            }
        }
        //IExecFilter接口
        public RT_VALUE onDatacenter(string name, ManagedObjectReference datecenterMor)
        {
            _vms.PrintLog(log_level.LOG_DEBUG, "on Datacenter:" + name + "...");
            curDatecenterMor = datecenterMor;
            curdatecenterName = name;
            foreach(express_op e in oplist)
            {
                if (string.Compare(e.name, "datacenter", true) == 0)
                {
                    return STR_CMP_RETURN(e.value, name, e.method, e.cond);                    
                }
            }            
            return RT_VALUE.CONTINUE;
        }
        public RT_VALUE onDomain(string name, ManagedObjectReference domainMor)
        {
            _vms.PrintLog(log_level.LOG_DEBUG, "on Domain:" + name + "...");
            curDomainMor = domainMor;
            foreach (express_op e in oplist)
            {
                if (string.Compare(e.name, "domain", true) == 0)
                {
                    return STR_CMP_RETURN(e.value, name, e.method, e.cond);
                }
            }
            return RT_VALUE.CONTINUE;
        }
        public RT_VALUE onStart(VmwreIterator vi)
        {
            _vms.PrintLog(log_level.LOG_INFO, "Exec in " + vi.GetServerIp() + "...");
            curVi = vi;
            return RT_VALUE.CONTINUE;
        }
        public RT_VALUE onEnd(VmwreIterator vi)
        {
            _vms.PrintLog(log_level.LOG_DEBUG, "Exec over in " + vi.GetServerIp() + "...");
            return RT_VALUE.CONTINUE;
        }
        public RT_VALUE onVm(string name, ManagedObjectReference vm)
        {
            _vms.PrintLog(log_level.LOG_DEBUG, "on Vm:" + name + "...");
            curvmname = name;
            curVmMor = vm;
            foreach (express_op e in oplist)
            {
                if (string.Compare(e.name, "vm", true) == 0)
                {
                    return STR_CMP_RETURN(e.value, name, e.method, e.cond);
                }
            }
            return RT_VALUE.CONTINUE;
        }
        public RT_VALUE onHost(string name, ManagedObjectReference hostMor)
        {
            _vms.PrintLog(log_level.LOG_DEBUG, "on Host:" + name + "...");
            curHostMor = hostMor;
            curhostsname = name;
            foreach (express_op e in oplist)
            {
                if (string.Compare(e.name, "host", true) == 0)
                {
                    return STR_CMP_RETURN(e.value, name, e.method, e.cond);
                }
            }
            return RT_VALUE.CONTINUE;
        }
        public RT_VALUE onDevice(VirtualDevice device)
        {
            string type = device.GetType().ToString();
            AppUtil.ServiceUtil _srvUtil = curVi.SrvUtil;
            if (device is VirtualEthernetCard)
            {
                string macaddr = ((VirtualEthernetCard)device).macAddress;
                //Console.WriteLine(" found netcard, macAddress:" + macaddr);
                //_vms.PrintLog(log_level.LOG_DEBUG, " found netcard, macAddress:" + macaddr);
                foreach (express_op e in oplist)
                {
                    if (string.Compare(e.name, "mac", true) == 0)
                    {
                        //return STR_CMP_RETURN(e.value, name, e.method, e.cond);
                        if (STR_CMP_RETURN(e.value, macaddr, e.method, e.cond) == RT_VALUE.CONTINUE)
                        //if (macaddr.Equals(strmac))
                        {
                            ManagedObjectReference resourcePool = _srvUtil.GetMoRefProp(curVmMor, "resourcePool");
                            Stack<string> resourcePoolNames = new Stack<string> { };
                            string resourcePoolName = (string)_srvUtil.GetDynamicProperty(resourcePool, "name");
                            resourcePoolNames.Push(resourcePoolName);
                            resourcePool = _srvUtil.GetMoRefProp(resourcePool, "parent");
                            //ManagedObjectReference parent = resourcePool;
                            while (resourcePool.type.Contains("ResourcePool"))
                            {
                                resourcePoolName = (string)_srvUtil.GetDynamicProperty(resourcePool, "name");
                                resourcePoolNames.Push(resourcePoolName);
                                resourcePool = _srvUtil.GetMoRefProp(resourcePool, "parent");
                            }

                            //
                            //Console.Write("find in: " + datecenterName + "/" + hostsname + "/");
                            //_vms.PrintLog(log_level.LOG_INFO, "find in: " + curdatecenterName + "/" + curhostsname + "/");
                            string path = "find in: " + curdatecenterName + "/" + curhostsname + "/";
                            while (resourcePoolNames.Count > 0)
                            {
                                //Console.Write(resourcePoolNames.Pop() + "/");
                                path += resourcePoolNames.Pop() + "/";
                            }
                            //Console.Write(curvmname);
                            _vms.PrintLog(log_level.LOG_INFO, path + curvmname);
                            return RT_VALUE.STOP;
                        }
                    }                    
                }
                
            }
            return RT_VALUE.CONTINUE;
        }

        public void onException(Exception e)
        {
            _vms.PrintLog(log_level.LOG_ERROR, e.ToString());
        }
    }
}
